Auto ModeのEKSでEBSを扱ってみた

Auto ModeのEKSでEBSを扱ってみた

昨日 EKS に Auto Mode が追加されました。

https://dev.classmethod.jp/articles/eks-auto-mode/

EBS CSI ドライバーの設定不要で、EBS を扱えるようになったので試してみました。

Auto Mode で何が解決されたか

EKS 上のコンテナから EBS を利用するためには、EBS CSI ドライバーをセットアップする必要がありました。
EKS アドオンとして利用しやすいようになってはいるものの、IAM ロールの設定やアドオンの追加が必要でした。
追加したアドオンは継続してアップグレードする必要もあり、EKS 利用時の面倒なポイントの一つでした。

https://docs.aws.amazon.com/eks/latest/userguide/ebs-csi.html

Auto Mode を利用することで、この辺りの設定を AWS 側にオフロード可能です。

やってみる

eksctl で Auto Mode のクラスターを作成します。
作成方法の詳細は下記を参考にして下さい。

https://dev.classmethod.jp/articles/create-auto-mode-eks-cluster-with-eksctl/

公式ドキュメントにシナリオが用意されているので、こちらに沿って試してみます。

https://docs.aws.amazon.com/eks/latest/userguide/sample-storage-workload.html

最初はほぼリソースが無い状態からスタートです。
EBS CSI driver 関連のリソースは何も見えないですね。

$ kubectl get all -A
NAMESPACE     NAME                                TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
default       service/kubernetes                  ClusterIP   10.100.0.1     <none>        443/TCP   60m
kube-system   service/eks-extension-metrics-api   ClusterIP   10.100.125.4   <none>        443/TCP   60m

最初からある Storage Class として、gp2 を利用するものが見つかります。

$ kubectl describe sc gp2 -A
Name:            gp2
IsDefaultClass:  No
Annotations:     kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"storage.k8s.io/v1","kind":"StorageClass","metadata":{"annotations":{},"name":"gp2"},"parameters":{"fsType":"ext4","type":"gp2"},"provisioner":"kubernetes.io/aws-ebs","volumeBindingMode":"WaitForFirstConsumer"}

Provisioner:           kubernetes.io/aws-ebs
Parameters:            fsType=ext4,type=gp2
AllowVolumeExpansion:  <unset>
MountOptions:          <none>
ReclaimPolicy:         Delete
VolumeBindingMode:     WaitForFirstConsumer
Events:                <none>

EKS Auto Mode で EBS を扱う場合は、ebs.csi.eks.amazonaws.com を参照するストレージクラスを作成する必要があります。

EKS Auto Mode does not create a StorageClass for you. You must create a StorageClass referencing ebs.csi.eks.amazonaws.com to use the storage capability of EKS Auto Mode.
https://docs.aws.amazon.com/eks/latest/userguide/create-storage-class.html

なので、シナリオ通りに gp3 を利用する Storage Class を作成していきます。

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: auto-ebs-sc
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: ebs.csi.eks.amazonaws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
  type: gp3
  encrypted: "true"

無事作成できました。

$ kubectl apply -f sc.yaml
storageclass.storage.k8s.io/auto-ebs-sc created

内容を確認します。

$ kubectl describe sc auto-ebs-sc
Name:            auto-ebs-sc
IsDefaultClass:  Yes
Annotations:     kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"storage.k8s.io/v1","kind":"StorageClass","metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"true"},"name":"auto-ebs-sc"},"parameters":{"encrypted":"true","type":"gp3"},"provisioner":"ebs.csi.eks.amazonaws.com","volumeBindingMode":"WaitForFirstConsumer"}
,storageclass.kubernetes.io/is-default-class=true
Provisioner:           ebs.csi.eks.amazonaws.com
Parameters:            encrypted=true,type=gp3
AllowVolumeExpansion:  <unset>
MountOptions:          <none>
ReclaimPolicy:         Delete
VolumeBindingMode:     WaitForFirstConsumer
Events:                <none>

EBS CSI driver をアドオンとして入れている時は Provisioner として ebs.csi.aws.com を指定していたので、この点は注意が必要です。

https://github.com/kubernetes-sigs/aws-ebs-csi-driver/blob/master/examples/kubernetes/block-volume/manifests/storageclass.yaml

provisioner: ebs.csi.eks.amazonaws.com - Uses EKS Auto Mode
https://docs.aws.amazon.com/eks/latest/userguide/sample-storage-workload.html

他は今まで通りですね(EKS というより Kubernetes の世界の設定なので、そりゃそうだって感じですが)。
PVC を作成していきます。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: auto-ebs-claim
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: auto-ebs-sc
  resources:
    requests:
      storage: 8Gi

kubectl apply を実行します。

$ kubectl apply -f pvc.yaml
persistentvolumeclaim/auto-ebs-claim created

無事 PVC が作成されました。

$ kubectl describe pvc auto-ebs-claim
Name:          auto-ebs-claim
Namespace:     default
StorageClass:  auto-ebs-sc
Status:        Pending
Volume:
Labels:        <none>
Annotations:   <none>
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:
Access Modes:
VolumeMode:    Filesystem
Used By:       <none>
Events:
  Type    Reason                Age               From                         Message
  ----    ------                ----              ----                         -------
  Normal  WaitForFirstConsumer  6s (x3 over 34s)  persistentvolume-controller  waiting for first consumer to be created before binding

PVC を利用するアプリケーションを作成します。
volumes セクションに記載されている通り、作成した PVC を利用して EBS ボリュームを /data にマウントします。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: inflate-stateful
spec:
  replicas: 1
  selector:
    matchLabels:
      app: inflate-stateful
  template:
    metadata:
      labels:
        app: inflate-stateful
    spec:
      terminationGracePeriodSeconds: 0
      nodeSelector:
        eks.amazonaws.com/compute-type: auto
      containers:
        - name: bash
          image: public.ecr.aws/docker/library/bash:4.4
          command: ["/usr/local/bin/bash"]
          args: ["-c", "while true; do echo $(date -u) >> /data/out.txt; sleep 60; done"]
          resources:
            requests:
              cpu: "1"
          volumeMounts:
            - name: persistent-storage
              mountPath: /data
      volumes:
        - name: persistent-storage
          persistentVolumeClaim:
            claimName: auto-ebs-claim

kubectl apply を実行します。

$ kubectl apply -f deployment.yaml
deployment.apps/inflate-stateful created

Pod が無事 Running になりました。

$ kubectl describe pod inflate-stateful-59db4c8c9-r6hql
Name:             inflate-stateful-59db4c8c9-r6hql
Namespace:        default
Priority:         0
Service Account:  default
Node:             i-0636543e5d522d31b/192.168.187.65
Start Time:       Tue, 03 Dec 2024 06:42:59 +0900
Labels:           app=inflate-stateful
                  pod-template-hash=59db4c8c9
Annotations:      <none>
Status:           Running
IP:               192.168.172.128
IPs:
  IP:           192.168.172.128
Controlled By:  ReplicaSet/inflate-stateful-59db4c8c9
Containers:
  bash:
    Container ID:  containerd://bec6b87f27347132cfdb6f75502c38e2af237747e95746537bf67218b2f8e771
    Image:         public.ecr.aws/docker/library/bash:4.4
    Image ID:      public.ecr.aws/docker/library/bash@sha256:347a41a463e19a852e1cc942eb0ef16d62e777038d311314b33da8c587472e40
    Port:          <none>
    Host Port:     <none>
    Command:
      /usr/local/bin/bash
    Args:
      -c
      while true; do echo $(date -u) >> /data/out.txt; sleep 60; done
    State:          Running
      Started:      Tue, 03 Dec 2024 06:43:19 +0900
    Ready:          True
    Restart Count:  0
    Requests:
      cpu:        1
    Environment:  <none>
    Mounts:
      /data from persistent-storage (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-htvxj (ro)
Conditions:
  Type                        Status
  PodReadyToStartContainers   True
  Initialized                 True
  Ready                       True
  ContainersReady             True
  PodScheduled                True
Volumes:
  persistent-storage:
    Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
    ClaimName:  auto-ebs-claim
    ReadOnly:   false
  kube-api-access-htvxj:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   Burstable
Node-Selectors:              eks.amazonaws.com/compute-type=auto
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type     Reason                  Age                    From                     Message
  ----     ------                  ----                   ----                     -------
  Normal   Nominated               2m31s                  karpenter                Pod should schedule on: nodeclaim/general-purpose-dzvt2
  Warning  FailedScheduling        2m16s (x5 over 2m32s)  default-scheduler        no nodes available to schedule pods
  Normal   Scheduled               2m3s                   default-scheduler        Successfully assigned default/inflate-stateful-59db4c8c9-r6hql to i-0636543e5d522d31b
  Normal   SuccessfulAttachVolume  2m1s                   attachdetach-controller  AttachVolume.Attach succeeded for volume "pvc-f1edb981-51a9-448e-9fc0-4454bcfa7676"
  Warning  FailedCreatePodSandBox  2m                     kubelet                  Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "fe28f5e6743534f765ac2a831e9ccd1938212a5e617efd5e413fb32b615aaea3": plugin type="aws-cni" name="aws-cni" failed (add): add cmd: Error received from AddNetwork gRPC call: rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing: dial tcp 127.0.0.1:50051: connect: connection refused"
  Normal   Pulling                 108s                   kubelet                  Pulling image "public.ecr.aws/docker/library/bash:4.4"
  Normal   Pulled                  104s                   kubelet                  Successfully pulled image "public.ecr.aws/docker/library/bash:4.4" in 4.075s (4.075s including waiting). Image size: 5985546 bytes.
  Normal   Created                 104s                   kubelet                  Created container bash
  Normal   Started                 104s                   kubelet                  Started container bash

PV も無事作成されています。

$ kubectl describe pv
Name:              pvc-f1edb981-51a9-448e-9fc0-4454bcfa7676
Labels:            <none>
Annotations:       pv.kubernetes.io/provisioned-by: ebs.csi.eks.amazonaws.com
                   volume.kubernetes.io/provisioner-deletion-secret-name:
                   volume.kubernetes.io/provisioner-deletion-secret-namespace:
Finalizers:        [external-provisioner.volume.kubernetes.io/finalizer kubernetes.io/pv-protection external-attacher/ebs-csi-eks-amazonaws-com]
StorageClass:      auto-ebs-sc
Status:            Bound
Claim:             default/auto-ebs-claim
Reclaim Policy:    Delete
Access Modes:      RWO
VolumeMode:        Filesystem
Capacity:          8Gi
Node Affinity:
  Required Terms:
    Term 0:        topology.kubernetes.io/zone in [ap-northeast-1a]
Message:
Source:
    Type:              CSI (a Container Storage Interface (CSI) volume source)
    Driver:            ebs.csi.eks.amazonaws.com
    FSType:            ext4
    VolumeHandle:      vol-05cf1cccb9405b33c
    ReadOnly:          false
    VolumeAttributes:      storage.kubernetes.io/csiProvisionerIdentity=1733171414036-3349-ebs.csi.eks.amazonaws.com
Events:                <none>

PVC も Bound 状態になりました。良さそうですね.

$ kubectl describe pvc auto-ebs-claim
Name:          auto-ebs-claim
Namespace:     default
StorageClass:  auto-ebs-sc
Status:        Bound
Volume:        pvc-f1edb981-51a9-448e-9fc0-4454bcfa7676
Labels:        <none>
Annotations:   pv.kubernetes.io/bind-completed: yes
               pv.kubernetes.io/bound-by-controller: yes
               volume.beta.kubernetes.io/storage-provisioner: ebs.csi.eks.amazonaws.com
               volume.kubernetes.io/selected-node: i-0636543e5d522d31b
               volume.kubernetes.io/storage-provisioner: ebs.csi.eks.amazonaws.com
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:      8Gi
Access Modes:  RWO
VolumeMode:    Filesystem
Used By:       inflate-stateful-59db4c8c9-r6hql
Events:
  Type    Reason                 Age                  From                                                                                              Message
  ----    ------                 ----                 ----                                                                                              -------
  Normal  WaitForFirstConsumer   68s (x8 over 2m51s)  persistentvolume-controller                                                                       waiting for first consumer to be created before binding
  Normal  WaitForPodScheduled    38s (x2 over 53s)    persistentvolume-controller                                                                       waiting for pod inflate-stateful-59db4c8c9-r6hql to be scheduled
  Normal  Provisioning           32s                  ebs.csi.eks.amazonaws.com_ebscsicontroller-85fd5cbdb9-ddlmj_e441b666-76fd-43ab-b307-8be43dbebfcc  External provisioner is provisioning volume for claim "default/auto-ebs-claim"
  Normal  ExternalProvisioning   32s (x2 over 32s)    persistentvolume-controller                                                                       Waiting for a volume to be created either by the external provisioner 'ebs.csi.eks.amazonaws.com' or manually by the system administrator. If volume creation is delayed, please verify that the provisioner is running and correctly registered.
  Normal  ProvisioningSucceeded  30s                  ebs.csi.eks.amazonaws.com_ebscsicontroller-85fd5cbdb9-ddlmj_e441b666-76fd-43ab-b307-8be43dbebfcc  Successfully provisioned volume pvc-f1edb981-51a9-448e-9fc0-4454bcfa7676

EBS を確認すると、指定した通り 8GiB で作成されています。

$ PV_NAME=$(kubectl get pvc auto-ebs-claim -o jsonpath='{.spec.volumeName}')
$ aws ec2 describe-volumes \
  --filters Name=tag:CSIVolumeName,Values=${PV_NAME}
{
    "Volumes": [
        {
            "Attachments": [
                {
                    "AttachTime": "2024-12-02T21:43:01+00:00",
                    "Device": "/dev/xvdaa",
                    "InstanceId": "i-0636543e5d522d31b",
                    "State": "attached",
                    "VolumeId": "vol-05cf1cccb9405b33c",
                    "DeleteOnTermination": false
                }
            ],
            "AvailabilityZone": "ap-northeast-1a",
            "CreateTime": "2024-12-02T21:42:57.416000+00:00",
            "Encrypted": true,
            "KmsKeyId": "arn:aws:kms:ap-northeast-1:xxxxxxxxxxxx:key/xxxxxxxxxxxxxxxx",
            "Size": 8,
            "SnapshotId": "",
            "State": "in-use",
            "VolumeId": "vol-05cf1cccb9405b33c",
            "Iops": 3000,
            "Tags": [
                {
                    "Key": "CSIVolumeName",
                    "Value": "pvc-f1edb981-51a9-448e-9fc0-4454bcfa7676"
                },
                {
                    "Key": "Name",
                    "Value": "test-cluster-dynamic-pvc-f1edb981-51a9-448e-9fc0-4454bcfa7676"
                },
                {
                    "Key": "eks:eks-cluster-name",
                    "Value": "test-cluster"
                },
                {
                    "Key": "kubernetes.io/created-for/pvc/namespace",
                    "Value": "default"
                },
                {
                    "Key": "kubernetes.io/created-for/pvc/name",
                    "Value": "auto-ebs-claim"
                },
                {
                    "Key": "KubernetesCluster",
                    "Value": "test-cluster"
                },
                {
                    "Key": "ebs.csi.eks.amazonaws.com/cluster",
                    "Value": "true"
                },
                {
                    "Key": "kubernetes.io/created-for/pv/name",
                    "Value": "pvc-f1edb981-51a9-448e-9fc0-4454bcfa7676"
                },
                {
                    "Key": "kubernetes.io/cluster/test-cluster",
                    "Value": "owned"
                }
            ],
            "VolumeType": "gp3",
            "MultiAttachEnabled": false,
            "Throughput": 125
        }
    ]
}

data としてボリュームをマウントしているので、そちらにファイルが出力されているかを確認します。

$ kubectl exec "$(kubectl get pods -l app=inflate-stateful \
  -o=jsonpath='{.items[0].metadata.name}')" -- \
  cat /data/out.txt
Mon Dec 2 21:43:19 UTC 2024
Mon Dec 2 21:44:19 UTC 2024
Mon Dec 2 21:45:19 UTC 2024
Mon Dec 2 21:46:19 UTC 2024
Mon Dec 2 21:47:19 UTC 2024
Mon Dec 2 21:48:19 UTC 2024

無事出力されていることを確認できました!

まとめ

めちゃめちゃ楽になりました!
とりあえず Auto Mode で始めるのが吉なように感じました。
個人的には EFS 辺りも最初から使えて良いのでは?と思ってますが、こちらはアドオンの追加が必要です。

https://dev.classmethod.jp/articles/csi-driver-for-amazon-efs-eks-addon/

いまアドオンの追加が必要なリソースも、選択式だけど AWS 管理みたいな扱いになると嬉しいなと思うのですが、贅沢ですかね。
その辺りのアップデートは今後に期待します!

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.